package cn.ibizlab.core.authentication.provider;

import cn.ibizlab.core.ad.domain.SysPerson;
import cn.ibizlab.core.authentication.constants.AuthenticationConstant;
import cn.ibizlab.core.authentication.domain.AuthProvider;
import cn.ibizlab.core.authentication.service.impl.AuthProviderServiceImpl;
import cn.ibizlab.core.authentication.service.impl.AuthUserServiceImpl;
import cn.ibizlab.core.authentication.service.impl.ServiceApiAuthenticationService;
import cn.ibizlab.util.enums.Entities;
import cn.ibizlab.util.errors.BadRequestAlertException;
import cn.ibizlab.util.security.AuthenticationUser;
import cn.ibizlab.util.service.AuthenticationUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

@Slf4j
@Component
public class ServiceApiAuthenticationProvider implements AuthenticationProvider {

    @Autowired
    AuthProviderServiceImpl authProviderService;
    @Autowired
    AuthUserServiceImpl authUserService;
    @Autowired
    AuthenticationUserService authenticationUserService;
    @Autowired
    AuthenticationServiceManager authenticationServiceManager;

    /**
     * 调用service api服务进行验证
     * @param authentication
     * @return
     * @throws AuthenticationException
     */
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {

        AuthProvider provider = authProviderService.first(AuthenticationConstant.PROVIDER_API);
        if (provider == null)
            throw new BadRequestAlertException("未配置认证服务", Entities.AUTH_PROVIDER.toString(), "First provider");

        ServiceApiAuthenticationService apiService = (ServiceApiAuthenticationService) authenticationServiceManager.getAuthenticationService(provider);
        String username = !ObjectUtils.isEmpty(authentication.getPrincipal()) ? authentication.getPrincipal().toString() : null;

        log.debug(String.format("正在使用[service api]认证方式对[%1$s]用户登录进行验证", username));
        Authentication authenticate = apiService.authenticate(authentication);
        if (authenticate == null) {
            log.error(String.format("使用[service api]认证方式验证[%1$s]用户登录失败，未能获取认证用户信息", username));
            return null;
        }

        //注销登录清除用户缓存
        authenticationUserService.resetByUsername(username);
        SysPerson person = (SysPerson) authenticate.getDetails();
        person.setUserPassword(authentication.getCredentials().toString());
        //同步用户到数据库
        authUserService.syncUser2DataBase(person, apiService.getServiceType());
        //获取当前用户信息(角色及权限)
        AuthenticationUser user = authenticationUserService.loadUserByUsername(username);
        //构造认证信息
        UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(user, authentication.getCredentials(), user.getAuthorities());
        result.setDetails(user);
        return result;
    }

    /**
     * 判断provider中是否有type = service api的配置 , 且 service api 配置优先级最高
     * @param authentication
     * @return
     */
    @Override
    public boolean supports(Class<?> authentication) {
        return authProviderService.first(AuthenticationConstant.PROVIDER_API) != null;
    }

}
